﻿//========================================================= 
/**@file LC_CmdDriver.h
 * @brief 
 * 
 * @date 2016-06-09   10:36:33
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_LC_CMDDRIVER_H_
#define _LIBZHOUYB_LC_CMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../lc/inc/LC_ComToCCID_CmdAdapter.h"
using zhou_yb::application::lc::LC_ComToCCID_CmdAdapter;

#include "../../lc/inc/LC_ReaderDevAdapter.h"
using zhou_yb::application::lc::LC_ReaderDevAdapter;

#include "../../lc/inc/LC_ComStreamCmdAdapter.h"
using zhou_yb::application::lc::LC_ComStreamCmdAdapter;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// LC串口协议命令驱动
class LC_CmdDriver : 
    public CommonCmdDriver,
    public BaseDevAdapterBehavior<IInteractiveTrans>
{
protected:
    Ref<IInteractiveTrans> _activeTrans;
    LC_ComStreamCmdAdapter _cmdAckAdapter;
    ComICCardCmdAdapter _cmdAdapter;
    LC_ComToCCID_CmdAdapter _lcCmdAdapter;
    LC_ReaderDevAdapter _lcAdapter;
public:
    LC_CmdDriver() : CommonCmdDriver()
    {
        _errGetter.Add(_lcAdapter)
            .New()
            .Add("LC_CMD", _lcCmdAdapter)
            .Select("ACK", _cmdAckAdapter)
            .End()
            .Add("IC_CMD", _cmdAdapter);

        select_helper<LoggerSetter::SelecterType>::select(_logSetter),
            _cmdAdapter, _cmdAckAdapter, _lcCmdAdapter, _lcAdapter;

        _lcCmdAdapter.SelectDevice(_cmdAdapter);
        _lcAdapter.SelectDevice(_lcCmdAdapter);

        _RegisteCMD(LC_CmdDriver, Verify);
        _RegisteCMD(LC_CmdDriver, Version);
        _RegisteCMD(LC_CmdDriver, GetSerialNumber);
        _RegisteCMD(LC_CmdDriver, SetSerialNumber);
        _RegisteCMD(LC_CmdDriver, GetPower);
        _RegisteCMD(LC_CmdDriver, IsAckMode);
        _RegisteCMD(LC_CmdDriver, SetAckMode);
        _RegisteCMD(LC_CmdDriver, SwitchToACK);
        _RegisteCMD(LC_CmdDriver, FetchJSON);
        _RegisteCMD(LC_CmdDriver, SaveJSON);

        _RegisteInterfaceCMD(LC_CmdDriver, IInteractiveTrans);
        _RegisteIInteractiveTransCMD(LC_CmdDriver);
        _RegisteAdapterCMD(LC_CmdDriver);
    }
    LC_CMD_INTERFACE_GETTER(IInteractiveTrans, _activeTrans);
    LC_CMD_INTERACTIVETRANS(_activeTrans);
    LC_CMD_METHOD(SelectDevice)
    {
        Ref<IInteractiveTrans> ref = CommandReflectArg(IInteractiveTrans, arg);
        if(ref.IsNull())
        {
            rlt.Put("Adapter", "IInteractiveTrans");
            _logErr(DeviceError::ArgIsNullErr, "IInteractiveTrans is null");
            return false;
        }
        if(ref == _pDev)
        {
            _logErr(DeviceError::ArgErr, "IInteractiveTrans is this");
            return false;
        }
        _pDev = ref;
        _cmdAdapter.SelectDevice(ref);
        _cmdAckAdapter.SelectDevice(ref);
        if(_activeTrans != _cmdAckAdapter)
        {
            _activeTrans = ref;
        }
        return true;
    }
    LC_CMD_METHOD(ReleaseDevice)
    {
        _pDev.Free();
        _activeTrans.Free();
        _cmdAckAdapter.ReleaseDevice();
        _cmdAckAdapter.ReleaseDevice();
        return true;
    }
    LC_CMD_METHOD(ActiveDevice)
    {
        if(_activeTrans.IsNull())
        {
            _logErr(DeviceError::DevInvalidErr);
            return false;
        }
        pointer p = reinterpret_cast<pointer>(&_activeTrans);
        rlt.Put("IInteractiveTrans", ArgConvert::ToString(p));
        return true;
    }
    /**
     * @brief 校验设备
     * @date 2016-11-01 09:21
     * 
     * @return 返回设备是否合法
     */
    LC_CMD_METHOD(Verify)
    {
        if(_lcAdapter.Verify())
            return true;

        _logErr(DeviceError::DevVerifyErr);
        return false;
    }
    /**
     * @brief 获取设备版本
     * @date 2016-06-09 10:50
     * 
     * @retval Version : string 获取到的版本
     * @retval VersionHex : hex 获取到的版本16进制格式
     */
    LC_CMD_METHOD(Version)
    {
        ByteBuilder version(8);
        if(!_lcAdapter.GetVersion(version))
            return false;

        rlt.Put("VersionHex", ArgConvert::ToString(version));
        ByteConvert::ToString(version);
        rlt.Put("Version", version.GetString());
        return true;
    }
    /**
     * @brief 返回当前ACK模式
     * @date 2016-10-08 20:34
     * 
     * @param [in] Send : hex 测试ACK发送的指令
     * 
     * @retval AckMode : bool 当前ACK模式 
     */
    LC_CMD_METHOD(IsAckMode)
    {
        string sCmd = arg["Send"].To<string>("");
        ByteBuilder cmdHex(8);
        DevCommand::FromAscii(sCmd.c_str(), cmdHex);

        if(cmdHex.IsEmpty())
        {
            _logErr(DeviceError::ArgErr, "缺少ACK握手指令:[Send]");
            return false;
        }

        bool isAck = _cmdAckAdapter.Write(cmdHex);
        rlt.Put("AckMode", ArgConvert::ToString(isAck));
        return true;
    }
    /**
     * @brief 设置ACK模式
     * @date 2016-06-09 10:50
     * 
     * @param [in] AckMode : bool 需要设置的ACK模式
     */
    LC_CMD_METHOD(SetAckMode)
    {
        bool isAck = arg["AckMode"].To<bool>(false);
        return _lcAdapter.SetAckMode(isAck);
    }
    /**
     * @brief 自动设置ACK模式
     * @date 2016-10-08 22:18
     * 
     * @param [in] IsCheckLRC : bool [default:true] ACK模式时,是否校验ACK的校验和
     * @param [in] IsAckMode : bool [default:true] 是否开启ACK模式
     * @param [in] Send : hex [default:1B 24 49] ACK握手时发送的指令数据
     */
    LC_CMD_METHOD(SwitchToACK)
    {
        string str = arg["Send"].To<string>("1B 24 49");
        ByteBuilder sCmd(8);
        DevCommand::FromAscii(str.c_str(), sCmd);
        if(sCmd.IsEmpty())
        {
            _logErr(DeviceError::ArgErr, "缺少参数:[Send]");
            return false;
        }
        bool isCheckLRC = arg["IsCheckLRC"].To<bool>(true);
        _cmdAckAdapter.IsCheckLRC = isCheckLRC;

        // 判断硬件实际的ACK状态
        bool isAckMode = _cmdAckAdapter.Write(sCmd);
        // 设备可能处于非ACK状态,或者设备已经断开连接
        if(!isAckMode)
        {
            if(!_pDev->Write(sCmd))
            {
                _logErr(DeviceError::DevStateErr, "设备断开连接");
                return false;
            }
        }
        bool isAck = arg["IsAckMode"].To<bool>(true);
        if(isAck == isAckMode)
            return true;
        // 使用当前模式发送切换指令
        _activeTrans = isAckMode ? _cmdAckAdapter : _pDev;
        _cmdAdapter.SelectDevice(_activeTrans);
        if(!_lcAdapter.SetAckMode(isAck))
            return false;
        // 设置当前ACK接口
        _activeTrans = isAck ? _cmdAckAdapter : _pDev;
        _cmdAdapter.SelectDevice(_activeTrans);
        return true;
    }
    /**
     * @brief 读取设备中保存的配置信息(JSON格式)
     * @date 2017-02-25 16:57
     * 
     * @retval DATA : string 获取到的配置信息
     */
    LC_CMD_METHOD(FetchJSON)
    {
        ByteBuilder buff(256);
        if(!LC_ReaderDevAdapter::ReadConfigureZone(_lcAdapter, buff, 64))
        {
            _logErr(DeviceError::OperatorErr, "读配置区数据失败");
            return false;
        }
        rlt.Put("DATA", buff.GetString());
        return true;
    }
    /**
     * @brief 保存配置信息到设备中(JSON格式)
     * @date 2017-02-25 16:58
     * 
     * @param [in] DATA : string 需要保存的配置信息
     */
    LC_CMD_METHOD(SaveJSON)
    {
        string sData;
        if(!arg.Get("DATA", sData))
        {
            _logErr(DeviceError::ArgErr, "缺少参数[DATA]");
            return false;
        }
        ByteArray buff(sData.c_str(), sData.length());
        if(!LC_ReaderDevAdapter::WriteConfigureZone(_lcAdapter, buff, 64))
        {
            _logErr(DeviceError::OperatorErr, "写配置区数据失败");
            return false;
        }
        return true;
    }
    /**
     * @brief 获取设备序列号
     * @date 2016-10-03 11:30
     *
     * @param [in] IsHex : bool [default:false] 序列号是否直接以16进制格式的字符串导出
     * 
     * @retval SerialNumber : string 获取到的序列号(32个字符以内,支持字母)
     */
    LC_CMD_METHOD(GetSerialNumber)
    {
        ByteBuilder serialNumber(64);
        if(!_lcAdapter.GetSerialNumber(serialNumber, 0, 64))
            return false;
        const char SN_KEY[] = "SerialNumber";
        bool isHex = arg["IsHex"].To<bool>(false);
        ByteConvert::ToString(isHex, serialNumber);
        rlt.Put(SN_KEY, serialNumber.GetString());
        return true;
    }
    /**
     * @brief 设置设备序列号
     * @date 2016-10-03 11:34
     * 
     * @param [in] IsHex : string [default:false] 序列号是否以16进制格式直接写入
     * @param [in] SerialNumber : string 需要修改的新序列号(64个字节以内,支持字母)
     */
    LC_CMD_METHOD(SetSerialNumber)
    {
        string serialNumber = arg["SerialNumber"].To<string>();
        ByteBuilder tmp(8);
        bool isHex = arg["IsHex"].To<bool>(false);
        if(isHex)
        {
            ByteConvert::FromAscii(serialNumber.c_str(), tmp);
        }
        else
        {
            tmp = serialNumber.c_str();
        }
        ByteConvert::Fill(tmp, 64, true, 0x00);
        return _lcAdapter.SetSerialNumber(tmp, 0);
    }
    /**
     * @brief 获取设备电量
     * @date 2016-10-03 11:35
     * 
     * @retval V : string 电压(精确到0.01V)
     * @retval E : uint 电量
     */
    LC_CMD_METHOD(GetPower)
    {
        uint v = 0;
        bool lastVal = _lcCmdAdapter.IsFormatRecv;
        _lcCmdAdapter.IsFormatRecv = false;
        if(!_lcAdapter.GetVoltage(v))
            return false;
        _lcCmdAdapter.IsFormatRecv = lastVal;
        v /= 2;
        
        uint e = LC_ReaderDevAdapter::VoltageToElectricity(v * 10);
        ByteBuilder tmp(8);
        // 精度为 0.01 v
        tmp.Format("%d.%d", v / 100, v % 100);
        rlt.Put("V", tmp.GetString());
        rlt.Put("E", ArgConvert::ToString<uint>(e));
        return true;
    }
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_LC_CMDDRIVER_H_
//========================================================= 